﻿/*
* Activity Tracking Log v0.1.1 - http://activitytrackinglog.codeplex.com
* Activity Tracking Log for ASP.Net & ASP.Net MVC
* Copyright (c) 2011 Vadim Burac
* Licensed under the Microsoft Public License (Ms-PL)
* http://activitytrackinglog.codeplex.com/license
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Web.UI.WebControls;
using ActivityTrackingLog.Utils;

namespace ActivityTrackingLog.Data
{
    public class GroupedDataItem : IComparable
    {
        #region private data

        private List<object> _dataContainer = null;

        #endregion

        #region public accessors

        public int CountColumnIdx { get; set; }
        public int GroupCount { get; set; }

        public List<object> GetFlatDataArray()
        {
            if (null == _dataContainer)
                return null;

            var newList = new List<object>(_dataContainer);
            if (CountColumnIdx >= 0 && CountColumnIdx <= newList.Count)
            {
                newList.Insert(CountColumnIdx, GroupCount);
            }

            return newList;
        }

        #endregion

        #region ctors

        public GroupedDataItem(List<object> data)
        {
            CountColumnIdx = -1;
            _dataContainer = data;
            if (null == _dataContainer)
                _dataContainer = new List<object>();
        }

        #endregion

        #region helpers

        internal static Comparison<GroupedDataItem> GetComparison(Dictionary<int, Enums.SortDirectionEnum> attributesSorting)
        {
            return new Comparison<GroupedDataItem>((item1, item2) =>
            {
                return item1.CompareTo(item2, attributesSorting);
            });
        }

        internal static IEnumerable<GroupedDataItem> GroupToFlatList(Utils.GroupResult groupData, int countColumnIdx)
        {
            if (null == groupData.SubGroups)
            {
                return new List<GroupedDataItem>(new[] { 
                    new GroupedDataItem(new List<object> { groupData.Key }) 
                    { 
                        GroupCount = groupData.Count,
                        CountColumnIdx = countColumnIdx
                    } 
                });
            }

            var result = new List<GroupedDataItem>();
            foreach (var subGroup in groupData.SubGroups)
            {
                var subGroupFlatTable = GroupToFlatList(subGroup, countColumnIdx);

                result.AddRange(subGroupFlatTable
                    .Select(groupedItem =>
                            {
                                groupedItem._dataContainer = new List<object>() { groupData.Key }.Concat(groupedItem._dataContainer).ToList();
                                return groupedItem;
                            }
                        ));
            }

            return result;
        }

        #endregion

        #region IComparable implementation

        public int CompareTo(object obj)
        {
            return CompareTo(obj, null);
        }

        private int CompareTo(object obj, Dictionary<int, Enums.SortDirectionEnum> attributesSorting)
        {
            int defaultResult = 0;
            if (obj is GroupedDataItem)
            {
                GroupedDataItem compareTo = obj as GroupedDataItem;
                // !!! both items should have equal number of data fields
                var thisData = this.GetFlatDataArray();
                var compareToData = compareTo.GetFlatDataArray();
                if (null == attributesSorting)
                {
                    for (int i = 0; i < thisData.Count(); i++)
                    {
                        int cmpRes = CompareDataFields(thisData[i], compareToData[i], Enums.SortDirectionEnum.Ascending);
                        if (cmpRes != 0)
                            return cmpRes;
                    }
                }
                else
                {
                    foreach (int dataIdx in attributesSorting.Keys)
                    {
                        if (thisData.Count > dataIdx && compareToData.Count > dataIdx)
                        {
                            int cmpRes = CompareDataFields(thisData[dataIdx], compareToData[dataIdx], attributesSorting[dataIdx]);
                            if (cmpRes != 0)
                                return cmpRes;
                        }
                    }
                }
            }

            return defaultResult;
        }

        private static int CompareDataFields(object val1, object val2, Enums.SortDirectionEnum dir)
        {
            int cmpRes = 0;
            int sorDir = dir == Enums.SortDirectionEnum.Ascending ? 1 : -1;
            if (null == val1 || null == val2)
            {
                cmpRes = val1 == val2 ? 0 : 1;
            }
            else
            {
                if (val1 is IComparable)
                {
                    cmpRes = (val1 as IComparable).CompareTo(val2);
                }
                else
                    cmpRes = val1.ToString().CompareTo(val2.ToString());
            }
            return cmpRes * sorDir;
        }

        #endregion
    }
}
